package com.example.auto.processor;

import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.StandardLocation;

/**
 * @Description TODO
 * @Author Benjamin
 * @Date 2021/12/4
 */
// 需要处理的注解类型，由于可能存在嵌套注解的可能，可以直接处理所有被注解类
@SupportedAnnotationTypes("*")
// 要求的Java版本
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BeanAutoProcessor extends AbstractProcessor {

  /** 用于输出日志文本 */
  private Messager messager;

  /** 用于生成文件 */
  private Filer filer;

  /** 用于保存所有bean类文件完整路径 */
  private Set<String> beanPathSet = new HashSet<>();

  /** 生成文件路径 */
  private String directoryPath = "META-INF/spring.factories";

  /** 自动装配的key */
  private String autoConfigKey =
      "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n\t";

  @Override
  public synchronized void init(ProcessingEnvironment processingEnv) {
    super.init(processingEnv);
    messager = processingEnv.getMessager();
    filer = processingEnv.getFiler();
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    //		注解处理器会多次处理相关注解类，当此方法返回TRUE时后续处理器就不再执行处理逻辑
    if (roundEnv.processingOver()) {
      //			相关处理完毕，需要生成spring.factories文件
      generateFile();
      return true;
    }
    //		处理相关被注解的类
    return doProcessor(roundEnv);
  }

  private boolean doProcessor(RoundEnvironment roundEnv) {
    //		获取所有类
    Set<? extends Element> rootElements = roundEnv.getRootElements();
    //		遍历所有类
    rootElements.forEach(
        element -> {
          //          缓存所有带BeanAuto注解的类
          List<? extends AnnotationMirror> mirrors =
              element.getAnnotationMirrors().stream()
                  .filter(
                      annotationMirror ->
                          annotationMirror
                              .getAnnotationType()
                              .toString()
                              .equals(BeanAuto.class.getName()))
                  .collect(Collectors.toList());
          if (mirrors.size() > 0) {
            beanPathSet.add(element.toString());
          }
        });
    return false;
  }

  private void generateFile() {
    messager.printMessage(Kind.NOTE, beanPathSet.toString());
    try (Writer writer =
        filer.createResource(StandardLocation.CLASS_OUTPUT, "", directoryPath).openWriter()) {
      writer.append(autoConfigKey);
      writer.append(String.join(",\\\n\t", beanPathSet));
      writer.flush();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
